package com.vavr.checkincms.service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.vavr.checkincms.common.constant.CommonConstants;
import com.vavr.checkincms.common.domain.ResultEnum;
import com.vavr.checkincms.common.exception.BaseException;
import com.vavr.checkincms.constant.CheckinConstants;
import com.vavr.checkincms.convert.MeetingParticipantConvert;
import com.vavr.checkincms.domain.bo.MeetingParticipantBO;
import com.vavr.checkincms.domain.data.CheckinRecordsDO;
import com.vavr.checkincms.domain.data.MeetingParticipantDO;
import com.vavr.checkincms.domain.data.MeetingUserParamDO;
import com.vavr.checkincms.domain.dto.CheckinUserDTO;
import com.vavr.checkincms.domain.dto.MeetingConfigDTO;
import com.vavr.checkincms.domain.dto.MeetingInfoDownloadDTO;
import com.vavr.checkincms.domain.dto.MeetingParticipantDTO;
import com.vavr.checkincms.mapper.CheckinRecordsMapper;
import com.vavr.checkincms.mapper.MeetingInfoMapper;
import com.vavr.checkincms.mapper.MeetingParticipantMapper;
import com.vavr.checkincms.mapper.MeetingUserParamMapper;
import com.vavr.checkincms.util.CheckinRequestUtils;
import com.vavr.checkincms.util.FileUtils;
import com.vavr.checkincms.util.ParamUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;

/**
 * MeetingParticipantServiceImpl
 *
 * @since 2024.08
 */
@Slf4j
@Service
public class MeetingParticipantServiceImpl implements MeetingParticipantService {
    /**
     * meetingParticipantMapper
     */
    private final MeetingParticipantMapper meetingParticipantMapper;

    /**
     * checkinRecordsMapper
     */
    private final CheckinRecordsMapper checkinRecordsMapper;

    /**
     * meetingInfoMapper
     */
    private final MeetingInfoMapper meetingInfoMapper;

    /**
     * meetingUserParamMapper
     */
    private final MeetingUserParamMapper meetingUserParamMapper;

    public MeetingParticipantServiceImpl(MeetingParticipantMapper meetingParticipantMapper,
            CheckinRecordsMapper checkinRecordsMapper, MeetingInfoMapper meetingInfoMapper,
            MeetingUserParamMapper meetingUserParamMapper) {
        this.meetingParticipantMapper = meetingParticipantMapper;
        this.checkinRecordsMapper = checkinRecordsMapper;
        this.meetingInfoMapper = meetingInfoMapper;
        this.meetingUserParamMapper = meetingUserParamMapper;
    }

    @Override
    public MeetingParticipantDTO getMeetingParticipantByTel(MeetingParticipantBO bo, HttpServletRequest request) {
        // 如果存在userId 直接根据userId 获取结果
        MeetingParticipantDTO meetingParticipant = getMeetingParticipant(bo, request);
        if (meetingParticipant != null) {
            meetingParticipant.setTel(ParamUtils.toDataMasking(meetingParticipant.getTel()));
            meetingParticipant.setParam(getMeetingUserParam(bo.getUserId()));
            MeetingParticipantDO participantDO = meetingParticipantMapper.selectById(bo.getUserId());
            if (meetingInfoMapper.queryMeetingInfo(bo.getMeetingId())
                    .stream()
                    .anyMatch(config -> CheckinConstants.ADMIN.equals(config.getConfigId()) && config.getConfigValue()
                            .equals(participantDO.getOpenId()))) {
                meetingParticipant.setAdmin(true);
            }
            return meetingParticipant;
        }
        return MeetingParticipantDTO.builder().build();
    }

    public MeetingParticipantDTO getMeetingParticipant(MeetingParticipantBO bo, HttpServletRequest request) {
        // 如果存在userId 直接根据userId 获取结果
        if (Strings.isNotBlank(bo.getUserId())) {
            MeetingParticipantDO participantDO = meetingParticipantMapper.selectById(bo.getUserId());
            if (participantDO != null) {
                return MeetingParticipantConvert.INSTANCE.doToDto(participantDO);
            }
        }

        // 如果存在cookie信息,根据会议查询用户信息,若存在,返回查询结果信息
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            Optional<MeetingParticipantDO> participantDOOptional = Arrays.stream(cookies)
                    .filter(v -> CommonConstants.CHECKIN_COOKIE_ID.equals(v.getName()))
                    .findAny()
                    .map(v -> meetingParticipantMapper.selectById(v.getValue()));
            if (participantDOOptional.isPresent() && bo.getMeetingId()
                    .equals(participantDOOptional.get().getMeetingId()) && Strings.isNotBlank(
                    participantDOOptional.get().getTel())) {
                // 若果存在同session_id的同会议数据且手机号不为空,返回该数据
                return MeetingParticipantConvert.INSTANCE.doToDto(participantDOOptional.get());
            }
        }

        // 如果存在会议id 先根据会议id 查询预先录入的
        if (Strings.isNotBlank(bo.getMeetingId())) {
            QueryWrapper<MeetingParticipantDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("meeting_id", bo.getMeetingId());
            queryWrapper.eq("tel", bo.getTel());
            MeetingParticipantDO meetingParticipantDO = meetingParticipantMapper.selectOne(queryWrapper);
            if (meetingParticipantDO != null) {
                return MeetingParticipantConvert.INSTANCE.doToDto(meetingParticipantDO);
            }
        }

        QueryWrapper<CheckinRecordsDO> wrapper = new QueryWrapper<>();
        wrapper.eq("meeting_id", bo.getMeetingId());
        wrapper.eq("tel", bo.getTel());
        List<CheckinRecordsDO> records = checkinRecordsMapper.selectList(wrapper);
        if (records != null && !records.isEmpty()) {
            CheckinRecordsDO checkRecord = records.stream()
                    .max(Comparator.comparing(CheckinRecordsDO::getCheckinTime))
                    .get();
            return MeetingParticipantDTO.builder()
                    .tel(checkRecord.getTel())
                    .name(checkRecord.getName())
                    .organization(checkRecord.getOrganization())
                    .build();
        }
        return MeetingParticipantDTO.builder().build();
    }

    @Override
    public List<MeetingParticipantDTO> getMeetingParticipantById(String meetingId) {
        QueryWrapper<MeetingParticipantDO> wrapper = new QueryWrapper<>();
        wrapper.eq("meeting_id", meetingId);
        List<MeetingParticipantDO> meetingParticipantDOS = meetingParticipantMapper.selectList(wrapper);
        if (meetingParticipantDOS != null) {
            return MeetingParticipantConvert.INSTANCE.doToDto(meetingParticipantDOS);
        }
        return List.of();
    }

    @Override
    public String addMeetingParticipant(MeetingParticipantBO bo, HttpServletRequest request) {
        // 需要判断是否存在userId, 如果不存在重新生成,进行新增,存在进行跟新
        int count = 0;
        if (bo == null || Strings.isEmpty(bo.getUserId()) || Strings.isEmpty(bo.getTel())) {
            throw new BaseException(ResultEnum.MISS_PARAM);
        }
        MeetingParticipantDO meetingParticipantDO = MeetingParticipantConvert.INSTANCE.boToDo(bo);
        UpdateWrapper<MeetingParticipantDO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", bo.getUserId())
                .set("name", bo.getName())
                .set("organization", bo.getOrganization())
                .set("group_id", bo.getGroupId());
        if (Strings.isNotBlank(bo.getTel()) && !bo.getTel().contains("****")) {
            updateWrapper.set("tel", bo.getTel());
        }
        count = meetingParticipantMapper.update(updateWrapper);
        updateUserParam(bo);
        return count > 0 ? ResultEnum.OK.getMsg() : ResultEnum.ERROR.getMsg();
    }

    @Override
    public String getMeetingUserParam(String userId) {
        JSONObject param = new JSONObject();
        QueryWrapper<MeetingUserParamDO> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        List<MeetingUserParamDO> meetingUserParams = meetingUserParamMapper.selectList(wrapper);
        if (!meetingUserParams.isEmpty()) {
            meetingUserParams.forEach(userParamDO -> param.put(userParamDO.getParamId(), userParamDO.getParamValue()));
        }
        if (param.containsKey("idCard") && Strings.isNotBlank(param.getString("idCard"))) {
            param.put("idCard", ParamUtils.toDataMasking(param.getString("idCard")));
        }
        return param.toJSONString();
    }

    @Override
    public void getAllUserInfo(MeetingParticipantBO bo, HttpServletResponse response, HttpServletRequest request) {
        String userId = bo.getUserId();
        if (Strings.isEmpty(userId)) {
            log.error("未登录");
            throw new BaseException(ResultEnum.NO_USER_INFO);
        }
        MeetingParticipantDO participantDO = meetingParticipantMapper.selectById(userId);
        if (participantDO == null) {
            log.error("未登录");
            throw new BaseException(ResultEnum.NO_USER_INFO);
        }
        MeetingConfigDTO meetingConfigDTO = meetingInfoMapper.queryMeetingInfo(bo.getMeetingId())
                .stream()
                .filter(config -> CheckinConstants.ADMIN.equals(config.getConfigId()) && config.getConfigValue()
                        .equals(participantDO.getOpenId()))
                .findAny()
                .orElse(null);
        if (meetingConfigDTO == null) {
            log.error("非管理员无操作权限");
            throw new BaseException(ResultEnum.NO_USER_INFO);
        }
        // 首先查询所有信息
        List<MeetingInfoDownloadDTO> userInfos = meetingUserParamMapper.getAllUserInfo(bo.getMeetingId());
        if (userInfos == null || userInfos.isEmpty()) {
            log.error("不存在能导出的数据,数据条数");
            throw new BaseException(ResultEnum.NO_USER_INFO);
        }
        userInfos = userInfos.stream()
                .filter(userInfo -> userInfo != null && Strings.isNotBlank(userInfo.getTel()))
                .toList()
                .stream()
                .peek(item -> {
                    if (item != null && "1".equals(item.getIsAttend())) {
                        item.setIsAttend("参加");
                    }
                    else if (item != null) {
                        item.setIsAttend("不参加");
                    }
                })
                .toList();
        String fileName = "meetingUserInfo_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));

        String tempFileUrl = meetingInfoMapper.queryMeetingInfo(bo.getMeetingId())
                .stream()
                .filter(config -> CheckinConstants.TEMP_DIR.equals(config.getConfigId()))
                .findFirst()
                .map(MeetingConfigDTO::getConfigValue)
                .orElse("") + "/" + fileName + ".xlsx";
        log.error("tempFileUrl:{}", tempFileUrl);

        FileUtils.exportExcel(response, tempFileUrl, userInfos, fileName);
    }

    private void updateUserParam(MeetingParticipantBO bo) {
        if (Strings.isEmpty(bo.getParam())) {
            return;
        }
        // 解析param信息
        JSONObject param = JSON.parseObject(bo.getParam());
        // 获取会议配置信息
        List<MeetingConfigDTO> meetingConfigs = meetingInfoMapper.queryMeetingInfo(bo.getMeetingId());
        if (meetingConfigs.isEmpty()) {
            return;
        }
        // 这里需要模糊处理的字段 后续根据数据处理
        QueryWrapper<MeetingUserParamDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", bo.getUserId()).eq("param_id", "idCard");
        MeetingUserParamDO idCard = meetingUserParamMapper.selectOne(queryWrapper);

        // 先把之前的数据删掉
        meetingUserParamMapper.deleteById(bo.getUserId());

        // 接下来新增本次参数信息
        meetingConfigs.stream()
                .filter(config -> CheckinConstants.USER_PARAM.equals(config.getConfigId()) && param.containsKey(
                        config.getConfigValue()))
                .forEach(config -> {
                    MeetingUserParamDO userParamDO = MeetingUserParamDO.builder()
                            .userId(bo.getUserId())
                            .paramId(config.getConfigValue())
                            .paramValue(param.getString(config.getConfigValue()))
                            .paramName(config.getConfigName())
                            .paramDesc(config.getConfigDesc())
                            .build();
                    if ("idCard".equals(userParamDO.getParamId()) && Strings.isNotBlank(userParamDO.getParamValue())
                            && userParamDO.getParamValue().contains("****")) {
                        meetingUserParamMapper.insert(idCard);
                    }
                    else {
                        meetingUserParamMapper.insert(userParamDO);
                    }
                });
    }
}
